package com.sunwayworld.basemodule.common.asynctask.comsumer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sunwayworld.basemodule.common.asynctask.bean.LimsAsynctaskBean;
import com.sunwayworld.basemodule.common.asynctask.bean.LimsAsynctaskScheduleBean;
import com.sunwayworld.basemodule.common.asynctask.comsumer.callback.TaskExecuteCallback;
import com.sunwayworld.basemodule.common.asynctask.config.AsyncTaskStatusEnum;
import com.sunwayworld.basemodule.common.asynctask.config.LimsAsyncTaskExecutor;
import com.sunwayworld.basemodule.common.asynctask.service.LimsAsynctaskScheduleService;
import com.sunwayworld.basemodule.common.asynctask.service.LimsAsynctaskService;
import com.sunwayworld.basemodule.common.asynctask.util.AsyncTaskExecutorHelper;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.utils.ClassUtils;
import com.sunwayworld.framework.utils.ObjectUtils;
import com.sunwayworld.framework.utils.ReflectionUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * @auther zhangs
 * @description
 * @date 2022/5/19
 */
public class AsyncTaskRunnable implements Runnable{
    private static final Logger logger = LogManager.getLogger(AsyncTaskRunnable.class);

    private LimsAsynctaskBean serverTask;

    public AsyncTaskRunnable(LimsAsynctaskBean serverTask) {
        this.serverTask = serverTask;
    }

    public LimsAsynctaskBean getServerTask() {
        return serverTask;
    }

    @Override
    public void run() {
        AsyncTaskExecutorHelper asyncTaskExecutorHelper = ApplicationContextHelper.getBean(AsyncTaskExecutorHelper.class);
        LimsAsyncTaskExecutor taskExecutor = asyncTaskExecutorHelper.getByExecutorName(serverTask.getExecutorName());
        if(taskExecutor==null){
            logger.error("taskExecutor is null");
            return;
        }

        int corePoolSize = taskExecutor.getCorePoolSize();
        int maxPoolSize = taskExecutor.getMaximumPoolSize();
        int activeCount = taskExecutor.getActiveCount();
        int poolSize = taskExecutor.getPoolSize();
        String name = taskExecutor.getName();
        int waitQueueSize = taskExecutor.getQueue().size();
        logger.info("taskId={},开始执行任务: corePoolSize={},maxPoolSize={},activeCount={},waitQueueSize={},poolSize={},name={}",serverTask.getTaskId(),corePoolSize,maxPoolSize,activeCount,waitQueueSize,poolSize,name);

        LimsAsynctaskService asynctaskService = ApplicationContextHelper.getBean(LimsAsynctaskService.class);
        PlatformTransactionManager transactionManager = ApplicationContextHelper.getBean(PlatformTransactionManager.class);
        //执行具体方法
        try {
            String serviceMethod = serverTask.getServiceMethod();
            if(ObjectUtils.isEmpty(serviceMethod)){
                throw new RuntimeException("serviceMethod is null");
            }

            int index = serviceMethod.lastIndexOf(".");
            String serviceName = serviceMethod.substring(0, index);
            String methodName = serviceMethod.substring(index + 1);
            Class<?> serviceClazz = ClassUtils.getClass(serviceName);
            Object service = ApplicationContextHelper.getBean(serviceClazz);
            //result可以返回一些异步任务中的错误码，或者方法直接抛异常
            Object result = null;
            if(!ObjectUtils.isEmpty(serverTask.getJsonParam())){
                JSONObject jsonObject = JSON.parseObject(serverTask.getJsonParam());
                Method method = ReflectionUtils.findMethod(serviceClazz, methodName, new Class[]{JSONObject.class});
                logger.info("execute serviceMethod={},parm={}",serviceMethod,jsonObject);
                result = ReflectionUtils.invokeMethod(method, service, new Object[]{jsonObject});
            }else{
                Method method = ReflectionUtils.findMethod(serviceClazz, methodName);
                logger.info("execute serviceMethod={}",serviceMethod);
                result = ReflectionUtils.invokeMethod(method,service);
            }
            serverTask.setExecStatus(AsyncTaskStatusEnum.executeSuccess.status);
            if(!ObjectUtils.isEmpty(result) && result instanceof String){
                serverTask.setErrMsg(ObjectUtils.toString(result));
            }else{
                serverTask.setErrMsg(null);
            }

        } catch (Throwable e) {
            logger.error("execute error",e);
            String message = null;
            if(e.getCause() instanceof InvocationTargetException){
                InvocationTargetException f = (InvocationTargetException) e.getCause();
                message = f.getTargetException().getMessage();
            }else{
                message = e.getMessage();
            }
            if(ObjectUtils.isEmpty(message)){
                message = ExceptionUtils.getStackTrace(e);
            }
            // serverTask.setErrMsg(TestDataJsonResult.parseString(false, LimsCode.RUNTIME_EXCEPTION,message));
            serverTask.setExecStatus(AsyncTaskStatusEnum.executeFail.status);

        }finally {
            TransactionStatus transactionExecute = transactionManager.getTransaction(new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW));
            try {
                serverTask.setExecCount(serverTask.getExecCount()+1);
                serverTask.setExecEndDate(LocalDateTime.now());
                asynctaskService.getDao().update(serverTask,"ExecStatus","ExecEndDate","ErrMsg","ExecCount");
                transactionManager.commit(transactionExecute);
            }catch (Throwable s){
                transactionManager.rollback(transactionExecute);
                logger.error("transactionManager error transactionExecute:{}",s);
            }
            logger.info("taskId={},执行报告任务结束");

            //任务执行完成，执行一个回调方法
            String serverId = serverTask.getServerId();
            String executorName = serverTask.getExecutorName();
            if(ObjectUtils.isEmpty(serverId) || ObjectUtils.isEmpty(executorName)){
                return;
            }
            LimsAsynctaskScheduleService asynctaskScheduleService = ApplicationContextHelper.getBean(LimsAsynctaskScheduleService.class);
            LimsAsynctaskScheduleBean asynctaskScheduleBean = asynctaskScheduleService.selectFirstByFilter(SearchFilter.instance().match("serverId",serverId).filter(MatchPattern.SEQ)
                                                                .match("executorId", executorName).filter(MatchPattern.SEQ));
            if(!ObjectUtils.isEmpty(asynctaskScheduleBean) && !ObjectUtils.isEmpty(asynctaskScheduleBean.getTaskExecuteCallback())){
                TaskExecuteCallback taskExecuteCallback = ApplicationContextHelper.getBean(asynctaskScheduleBean.getTaskExecuteCallback());
                if(taskExecuteCallback!=null){
                    taskExecuteCallback.callBack(serverTask);
                }
            }
        }
    }
}
